import { Ref } from "vue";
import CryptoJS from "crypto-js";
const APPID = "cc8dc4bf";
const API_SECRET = "ZThkNzJhZTA4MDMxZjlmZjEwYTA0YjNk";
const API_KEY = "e1ee9985b4537df43cfb73e67d3b9f18";

/**
 * 获取携带token的  webscoket url
 * @param href 如果携带了连接，则以此为准
 * @returns url
 */
export const getWebsocketUrl = (
  apiKey?: string,
  apiSecret?: string
): string => {
  apiKey = apiKey ?? API_KEY;
  apiSecret = apiSecret ?? API_SECRET;

  var url = `wss://spark-api.xf-yun.com/v1.1/chat`;
  var host = location.host;
  var date = (new Date() as any).toGMTString();
  var algorithm = "hmac-sha256";
  var headers = "host date request-line";
  let version: string = "";
  version = "/v1.1/chat";
  var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${version} HTTP/1.1`;
  var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
  var signature = CryptoJS.enc.Base64.stringify(signatureSha);
  var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
  var authorization = btoa(authorizationOrigin);
  url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;

  return url;
};

/**
 * websockets 封装类
 */
class SocketsXinghuo {
  url?: string; // 连接地址
  socket?: WebSocket; // socket实类
  isOnline: Ref<boolean>; // 是否连接 , 这里是考虑到每次只能发送一条，一条结束前，为true则不能让人继续发消息
  APPID: string;
  data: string[]; // 一条消息星火模型会多次webscoket 返回，所以进行拼接
  resolve?: any; // 成功后的回调
  constructor(option?: ChatOption) {
    this.socket = undefined;
    this.isOnline = ref(false);
    this.url = getWebsocketUrl(option?.API_KEY, option?.API_SECRET);
    this.APPID = option?.APPID ?? APPID;
    this.APPID = option?.APPID ?? APPID;
    // 合并的消息
    this.data = [];
    this.resolve = undefined;
  }

  /**
   * 连接url
   * @returns WebSocket
   */
  connectSocket() {
    return new Promise((resolve, reject) => {
      if (this.socket && this.isOnline.value) {
        resolve(this.socket);
      } else {
        const url = this.url!;
        this.socket = new WebSocket(url);
        // 监听连接成功
        // 监听连接成功
        this.socket.onopen = () => {
          this.isOnline.value = true;
          resolve(this.socket);
        };
        // 监听接收信息
        this.socket.onmessage = (e) => this.onMessage(e);
        // 监听断开
        this.socket.onclose = (e) => this.onclose();
        // 监听错误
        this.socket.onerror = (err) => {
          this.isOnline.value = false;
        };
      }
    });
  }
  onclose() {
    console.log("关闭");
  }
  /**
   * 收到消息
   * @param data ChatFace
   */
  onMessage(data: MessageData) {
    const obj: ChatFace = JSON.parse(data.data);
    const arrText = obj.payload.choices.text;
    arrText.forEach((item) => {
      this.data.push(item.content);
    });
    if (obj.header.status === 2) {
      this.resolve && this.resolve(this.data.join("\r\n"));
      this.close();
    }
  }
  /**
   * 主动关闭，暂时无用
   */
  close() {
    this.socket?.close();
    this.socket = undefined;
    this.isOnline.value = false;
    this.data = [];
    this.resolve = undefined;
  }
  getParams(str: string) {
    return {
      header: {
        app_id: this.APPID,
      },
      parameter: {
        chat: {
          domain: "general",
          temperature: 0.5,
          max_tokens: 1024,
        },
      },
      payload: {
        message: {
          text: [{ role: "user", content: str }],
        },
      },
    };
  }
  /**
   * 发送消息
   * @param str  发送的消息文字
   * @returns
   */
  send(str: string): Promise<string > {
    return new Promise((resolve, reject) => {
      this.connectSocket().then((res) => {
        const params = this.getParams(str);
        this.resolve = resolve;
        this.socket?.send(JSON.stringify(params));
      });
    });
  }
}
export default SocketsXinghuo




interface MessageData {
    data: string;
  }
/**
 * 组件传入的字段
 */
interface ChatOption {
  uid?: string; // 传入的用户id
  url?: string; // 连接
  APPID?: string; // 传入的appid，便于让用户用自己的使用
  API_SECRET?: string;
  API_KEY?: string;
}

interface ChatFace {
    header: {
      /**
       * 错误码，0表示正常，非0表示出错；详细释义可在接口说明文档最后的错误码说明了解
       */
      code: number;
      /**
       * 会话是否成功的描述信息
       */
      message: string;
      /**
       * 会话的唯一id，用于讯飞技术人员查询服务端会话日志使用,出现调用错误时建议留存该字段
       */
      sid: string;
      /**
       * 会话状态，取值为[0,1,2]；0代表首次结果；1代表中间结果；2代表最后一个结果
       */
      status: number;
    };
    payload: {
      choices: {
        /**
         * 文本响应状态，取值为[0,1,2]; 0代表首个文本结果；1代表中间文本结果；2代表最后一个文本结果
         */
        status: number;
        /**
         * 返回的数据序号，取值为[0,9999999]
         */
        seq: number;
        /**
         * 回复的对象 数组格式，但是没看见过2条，就当是数组循环吧！
         */
        text: [
          {
            /**
             * AI的回答内容
             */
            content: string;
            /**
             * 角色标识，固定为assistant，标识角色为AI
             */
            role: "assistant";
            /**
             * 结果序号，取值为[0,10]; 当前为保留字段，开发者可忽略
             */
            index: number;
          }
        ];
      };
      usage: {
        text: {
          /**
           * 保留字段，可忽略
           */
          question_tokens: number;
          /**
           * 包含历史问题的总tokens大小
           */
          prompt_tokens: number;
          /**
           * 回答的tokens大小
           */
          completion_tokens: number;
          /**
           * prompt_tokens和completion_tokens的和，也是本次交互计费的tokens大小
           */
          total_tokens: number;
        };
      };
    };
  }